// 1. use type
// 2. use name
// 3. default false
// 4. template partial and inheritance
// static usually mean compile-time, dynamic run-time
// use of constexpr

namespace lei {

// 整数求绝对值
template <int N>
struct abs {
  static_assert(N != INT_MIN);
  static constexpr int value = (N > 0) ? N : -N;
};

// 求gcd
template <unsigned M, unsigned N>
struct gcd {
  static constexpr int value = gcd<M, M % N>::value;
};
template <unsigned M>
struct gcd<M, 0> {
  static_assert(M != 0);
  static constexpr int value = M;
};

template <typename T>
struct remove_const {
  using type = T;
};
template <typename T>
struct remove_const<T const> {
  using type = T;
};
// using remove_const_t<T> = remove_const<T>::type; from C++14

// important!
template <typename T>
struct type_is {
  using type = T;
};

template <typename T>
struct remove_volatile : type_is<T> {};
template <typename T>
struct remove_volatile<T volatile> : type_is<T> {};
// remove_cv
template <typename T>
using remove_cv = remove_volatile<remove_const<T>>;
template <typename T>
using remove_cv_t = typename remove_cv<T>::type;

// if结构
template <bool flag, typename T, typename>
struct conditional : type_is<T> {};
template <typename T, typename F>
struct conditional<false, T, F> : type_is<F> {};

// enable_if，if true, use the given type; else use no type at all
template <bool flag, typename T = void>
struct enable_if : type_is<T> {};
template <typename T>
struct enable_if<false, T> {};  // no member named type!

// true_type, false_type
template <typename T, T v>
struct integral_constant {
  static constexpr T value = v;
  constexpr operator T() const noexcept { return value; }
  constexpr T operator()() const noexcept { return value; }
};
template <bool b>
using bool_constant = integral_constant<bool, b>;
using true_type = bool_constant<true>;
using false_type = bool_constant<false>;

// has_type_member
// template <typename...>
// using void_t = void;
template <typename...>
struct voider {
  using type = void;
};
template <typename... T0toN>
using void_t = typename voider<T0toN...>::type;
// 为什么需要一个void的别名？不需要，这是需要一个可以预测的东西，void换成其他也可以
// 比如用于has_type_member中
// has_type_member
template <typename, typename = void>
struct has_type_member : false_type {};
template <typename T>
struct has_type_member<T, void_t<typename T::type>> : true_type {};
// 第二个只是对void包装了一层，但编译器通过重载决议可以有两条路走，牛啊!
// 可以扩展到has_xxx_member

// is_one_of
template <typename T, typename... P0toN>
struct is_one_of;
template <typename T>
struct is_one_of<T> : false_type {};
template <typename T, typename... P1toN>
struct is_one_of<T, T, P1toN...> : true_type {};
template <typename T, typename P0, typename... P1toN>
struct is_one_of<T, P0, P1toN...> : is_one_of<T, P1toN...> {};

// is_void
// template <typename T>
// using is_void = is_same<remove_cv_t<T>, void>;
template <typename T>
struct is_void : false_type {};
template <>
struct is_void<void> : true_type {};
template <>
struct is_void<void const> : true_type {};
// T 与 T const, 顶层const TODO:

// is_same
template <typename T, typename U>
struct is_same : false_type {};
template <typename T>
struct is_same<T, T> : true_type {};

}  // namespace lei
   // _t _v TODO: